// Modal
var Modal = function () {
  var self = this;
  var id = null;
  var opts = null;
  var template =
    '<div class="modal fade" id="' + id + '">' +
      '<div class="modal-dialog">' +
        '<div class="modal-content">' +
          '<div class="modal-header" data-bind="visible: title">' +
            '<button type="button" class="close" data-bind="visible: showCloseButton, click: close"><span aria-hidden="true">&times;</span></button>' +
            '<h4 class="modal-title" data-bind="html: title"></h4>' +
          '</div>' +
          '<div class="modal-body" data-bind="html: body"></div>' +
          '<div class="modal-footer">' +
            '<!-- ko foreach: buttons -->' +
            '<button type="button" data-bind="attr: { \'id\': id, \'class\': \'btn \' + className }, html: text, click: $parent.onButtonClick"></button>' +
            '<!-- /ko -->' +
          '</div>' +
        '</div>' +
      '</div>' +
    '</div>';
  var defer = null;
  var model = null;

  self.$modal = function () {
    return $('#' + id);
  };

  self.defer = function () {
    return defer;
  };

  self.open = function (options) {
    opts = options;

    if (options && options.buttons) {
      $.each(options.buttons, function () {
        if (!this.id) {
          this.id = '__btn_' + new Date().getTime() + Math.floor(Math.random() * 1000);
        }
        if (!this.className) {
          this.className = 'btn-default';
        }
      })
    }

    model = {
      title: ko.observable(options.title),
      body: ko.observable(options.body),
      showCloseButton: ko.observable(true),
      buttons: ko.observableArray(options.buttons),
      close: function () {
        self.close();
      },
      onButtonClick: function (button, e) {
        if (button.click) {
          button.click.apply(self, [e]);
        }
      }
    };

    if (options.showCloseButton !== undefined) {
      model.showCloseButton(options.showCloseButton);
    }

    id = '__modal_' + new Date().getTime();

    $(document.body).append($(template).attr('id', id));
    ko.applyBindings(model, document.getElementById(id));

    var $modal = $('#' + id);

    if (options) {
      $modal.modal(options);
    }

    $modal.on('shown.bs.modal', function () {
      _.each(options.buttons, function (button) {
          if (button.clipboard) {
            var clipboard = new Clipboard('#' + button.id, button.clipboard);
            if (button.clipboard.success) {
              clipboard.on('success', button.clipboard.success.bind(self));
            }
          }
      });

      if (opts.callbacks && opts.callbacks.shown) {
        opts.callbacks.shown.apply(self);
      }
    });

    self.resize();

    $modal.modal('show');

    defer = $.Deferred();

    return defer.promise();
  };

  self.resize = function () {
    var winHeight = $(window).height();
    $('#' + id)
      .find('.modal-body')
      .css('max-height', Math.round(winHeight * 0.7) + 'px')
      .css('overflow', 'auto');
  };

  self.close = function (options) {
    var $modal = $('#' + id);

    $modal.modal('hide');
    $modal.on('hidden.bs.modal', function () {
      $modal.remove();
    });

    if (opts.callbacks && opts.callbacks.close) {
      opts.callbacks.close.apply(self);
    }

    if (options && options.reject) {
      defer.reject();
    } else {
      defer.resolve();
    }
  };
};

Modal.instance = new Modal();

Modal.open = function (options) {
  return Modal.instance.open(options);
};

Modal.alert = function (options) {
  return Modal.instance.open({
    title: options.title,
    body: options.message,
    showCloseButton: false,
    buttons: options.buttons || [
      {
        'className': 'btn-primary',
        'text': '确定',
        'click': function () {
          this.close();
        }
      }
    ]
  })
};